/*
 * Line.java  0.4.0 / Oct 24, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
package com.cute4j.swing.graphics;

import java.util.NoSuchElementException;

/**
 * Line Shape.
 *
 * @author Slobodan Vrkacevic
 * @version 0.4.0
 */
public class Line implements Shape {

// Private Fields. -------------------------------------------------------------

  private final Point p1;
  private final Point p2;
  private Rectangle bounds; // NOPMD
  private int hashCode; // NOPMD

// Public Constructors. --------------------------------------------------------

  /**
   * Constructs new Line object.
   */
  public Line() {
    p1 = new Point();
    p2 = new Point();
  }

  /**
   * Constructs new Line object.
   *
   * @param x1 the x coordinate of the first point
   * @param y1 the y coordinate of the first point
   * @param x2 the x coordinate of the second point
   * @param y2 the y coordinate of the second point
   */
  public Line(int x1, int y1, int x2, int y2) {
    p1 = new Point(x1, y1);
    p2 = new Point(x2, y2);
  }

  /**
   * Constructs new Line object.
   *
   * @param p1 the first point
   * @param p2 the second point
   *
   * @throws IllegalArgumentException is <tt>p1</tt> or <tt>p2</tt> is
   *         <tt>null</tt>
   */
  public Line(Point p1, Point p2) {
    if (p1 == null) {
      throw new IllegalArgumentException("Null p1 point");
    }
    if (p2 == null) {
      throw new IllegalArgumentException("Null p2 point");
    }
    this.p1 = p1;
    this.p2 = p2;
  }

// Public Methods. -------------------------------------------------------------

  /**
   * Returns the x coordinate of the first point.
   *
   * @return the x coordinate of the first point
   */
  public int getX1() {
    return p1.getX();
  }

  /**
   * Returns the y coordinate of the first point.
   *
   * @return the y coordinate of the first point
   */
  public int getY1() {
    return p1.getY();
  }

  /**
   * Returns the x coordinate of the second point.
   *
   * @return the x coordinate of the second point
   */
  public int getX2() {
    return p2.getX();
  }

  /**
   * Returns the y coordinate of the second point.
   *
   * @return the y coordinate of the second point
   */
  public int getY2() {
    return p2.getY();
  }

// Shape Interface Implementation. ---------------------------------------------

  /**
   * {@inheritDoc}
   */
  public boolean contains(int x, int y) {
    return false;
  }

  /**
   * {@inheritDoc}
   */
  public Rectangle getBounds() {
    if (bounds == null) {
      int x;
      int y;
      int w;
      int h;
      if (getX1() < getX2()) {
        x = getX1();
        w = getX2() - getX1();
      } else {
        x = getX2();
        w = getX1() - getX2();
      }
      if (getY1() < getY2()) {
        y = getY1();
        h = getY2() - getY1();
      } else {
        y = getY2();
        h = getY1() - getY2();
      }
      bounds = new Rectangle(x, y, w, h);
    }
    return bounds;
  }

  /**
   * {@inheritDoc}
   */
  public PathIterator getPathIterator() {
    return new LinePathIterator(this);
  }

// Overridden Methods. ---------------------------------------------------------

  /**
   * {@inheritDoc}
   */
  public boolean equals(Object obj) {
    if (obj == this) {
      return true;
    }
    if ((obj != null) && (obj.getClass() == getClass())) {
      Line l = (Line)obj;
      return ((l.getX1() == getX1()) && (l.getY1() == getY1()) &&
              (l.getX2() == getX2()) && (l.getY2() == getY2()));
    }
    return false;
  }

  /**
   * {@inheritDoc}
   */
  public int hashCode() {
    if (hashCode == 0) {
      int hashCode = 59;
      hashCode = 151 * hashCode + getX1();
      hashCode = 151 * hashCode + getY1();
      hashCode = 151 * hashCode + getX2();
      hashCode = 151 * hashCode + getY2();
      this.hashCode = hashCode;
    }
    return hashCode;
  }

  /**
   * {@inheritDoc}
   */
  public String toString() {
    return getClass().getName() + "[x1=" + getX1() + ",y1=" + getY1() +
           ",x2=" + getX2() + ",y2=" + getY2() + "]";
  }

// Inner Classes. --------------------------------------------------------------

  /**
   * Line Path Iterator.
   */
  protected static class LinePathIterator implements PathIterator {

    private final Line line;
    private int iteration;

    /**
     * Constructs new LinePathIterator object.
     *
     * @param line the line
     */
    public LinePathIterator(Line line) {
      this.line = line;
    }

    /**
     * {@inheritDoc}
     */
    public int getWindingRule() {
      return WIND_NON_ZERO;
    }

    /**
     * {@inheritDoc}
     */
    public boolean isDone() {
      return (iteration > 1);
    }

    /**
     * {@inheritDoc}
     */
    public void next() {
      iteration++;
    }

    /**
     * {@inheritDoc}
     */
    public int currentSegment(int[] coords) {
      switch (iteration) {
        case 0:
          coords[0] = line.getX1();
          coords[1] = line.getY1();
          return SEG_MOVETO;
        case 1:
          coords[0] = line.getX2();
          coords[1] = line.getY2();
          return SEG_LINETO;
        default:
          throw new NoSuchElementException("Line Path Iterator out of bounds");
      }
    }

  }

}
